home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- **
- ** Project Name: DropInfo
- ** File Name: DIStuff.c
- **
- ** Description: Contains the DropInfo-specific code
- **
- *******************************************************************************
- ** A U T H O R I D E N T I T Y
- *******************************************************************************
- **
- ** Initials Name
- ** -------- -----------------------------------------------
- ** SCS Stephan Somogyi
- ** LDR Leonard Rosenthol
- **
- *******************************************************************************
- ** R E V I S I O N H I S T O R Y
- *******************************************************************************
- **
- ** Date Vers Author Description
- ** -------- ----- ------ ---------------------------------------------
- ** 22.12.91 LDR Changed an ExitToShell into a SendQuitToSelf
- **
- ** 06.09.91 a(-1) SCS files implemented except for resmap locking
- ** 10.09.91 a2 removed resmap locking as there is no nice way to do it
- ** added folders, not sure they work the way they should, though…
- ** 25.09.91 a3 added the laurie gill feature: cmd-q quits regardless of whether
- ** there are any files/folders left to deal with. added flushvols.
- ** 26.09.91 a4 added change all. fixed some stupid a3 bugs.
- ** 27.09.91 b1 added dimming of change all if only one file dropped. source
- ** reality check.
- ** 01.10.91 b1 changed oapp behavior to what it should be. better volume supt.
- ** 09.10.91 fc1 moved initial selection to type rather than creator
- ** fc2 minor divergence where SCS and LDR both did similar things
- ** 29.11.91 fc3 used 11/24/91 DropShell
- ** made non-inline MyBitTst and MyBitSetClr
- ** made DI compilable by both THINK and MPW
- ** 30.11.91 fc3+ LDR made MUCH more use of enum's & #defines rather than hard coded values
- ** Also added some comments
- ** Applied hack in ItsADir for MPW C compiler
- ** 01.12.91 F4 SCS Reformatting and commenting
- ** Replaced IUEqualString with EqualString for better case sensitivity
- **
- ******************************************************************************/
-
- #ifndef THINK_C
- #define TRUE true
- #define FALSE false
-
- #include <Dialogs.h>
- #include <Files.h>
- #include <Memory.h>
- #endif
-
-
- #include "DIUtils.h"
-
- #include "DIStuff.h"
-
-
- /* bit numbers for the relevant flags in the FInfo struct */
- enum {
- bIsLocked = 0,
- bIsDir = 4,
- bIsShared = 6,
- bHasNoINITs,
- bInited,
- bCustomIcn = 10,
- bStationary,
- bNameLock,
- bBundle,
- bInvisible,
- bIsAlias
- };
-
- /* contains the various bits' states
- [0] dirty flag, if anything is changed and needs to be saved this is TRUE
- [1] file locked state
- */
- static Boolean fileBits[bIsAlias];
-
- /* tells us whether to quit and ignore any other FSSpecs */
- static Boolean gAbort;
-
- /* tells us if change all is in effect, if it's files or folders, and whether the user
- has already been warned about mixing the two */
- Boolean gChgAll = 0, gIsFiles, gWarned = 0;
-
- /* these are globals since in ChgAll mode we're doing bunches of files/folders */
- static Str255 gTypeStr, gCreaStr;
-
- /* this is a global because it is reused when we're processing a volume */
- static Str255 gTempStr;
-
- /* is there only one file/folder in the list */
- Boolean gOnlyOne = 0;
-
-
- /* Does a bit test in 68k order, not the reverse like the Toolbox's BitTst() */
- Boolean
- MyBitTst(unsigned short pBMap, unsigned short pBitNum)
- {
- #ifdef THINK_C
- asm {
- moveq #0,d0
- moveq #0,d1
- move.w pBMap,d0
- move.w pBitNum,d1
- btst d1,d0
- beq.s @1
- moveq #1,d0
- bra.s @2
- @1: moveq #0,d0
- @2:
- }
- #else
-
- short lAndMap;
-
- lAndMap = 1 << pBitNum;
-
- if (pBMap & lAndMap)
- return TRUE;
- else
- return FALSE;
-
- #endif
- }
-
-
- /* Clears or sets the specified bit depending on pState */
- void
- MyBitSetClr(unsigned short *pBMap, unsigned short pBitNum, Boolean pState)
- {
- #ifdef THINK_C
- asm {
- move.l pBMap,a0
- moveq #0,d1
- move.w pBitNum, d1
-
- tst.b pState
- beq.s @1
-
- cmp.w #7,d1
- bgt.s @2
- bset d1,1(a0)
- bra.s @4
-
- @2: subq.w #8,d1
- bset d1,(a0)
- bra.s @4
-
- @1: cmp.w #7,d1
- bgt.s @3
- bclr d1,1(a0)
- bra.s @4
-
- @3: subq.w #8,d1
- bclr d1,(a0)
- @4:
- }
- #else
-
- short lOrMap;
-
- lOrMap = 1 << pBitNum;
-
- if (pState)
- (*pBMap) |= lOrMap;
- else {
- if (*pBMap & lOrMap)
- (*pBMap) ^= lOrMap;
- }
-
- #endif
- }
-
-
- /* toggles a Boolean and sets the dirty flag as well */
- void
- ToggleBit(Boolean *pBool)
- {
- if (*pBool)
- (*pBool) = FALSE;
- else
- (*pBool) = TRUE;
-
- fileBits[0] = TRUE; // set dirty flag
- }
-
-
- /* Takes a file's or folder's information and puts it in the right places in
- DI's array
- */
- void
- InfoIn(unsigned short pFSflags, CInfoPBPtr pCBlk)
- {
-
- short lCtr;
-
- if (!MyBitTst(pCBlk->hFileInfo.ioFlAttrib, bIsDir)) { // if not dir
- for (lCtr = bIsShared; lCtr <= bIsAlias; lCtr++) {
- if (MyBitTst(pFSflags, lCtr))
- fileBits[lCtr] = TRUE;
- else
- fileBits[lCtr] = FALSE;
- }
-
- if (MyBitTst(pCBlk->hFileInfo.ioFlAttrib,bIsLocked))
- fileBits[1] = TRUE; // file lock state
- else
- fileBits[1] = FALSE;
-
- fileBits[0] = FALSE; // dirty flag clear
- }
- else { // it's a dir
- if (MyBitTst(pCBlk->hFileInfo.ioFlFndrInfo.fdFlags,bInvisible)) // invisible
- fileBits[7] = TRUE;
- else
- fileBits[7] = FALSE;
-
- if (MyBitTst(pCBlk->hFileInfo.ioFlFndrInfo.fdFlags,bNameLock)) // locked name
- fileBits[6] = TRUE;
- else
- fileBits[6] = FALSE;
-
- if (MyBitTst(pCBlk->hFileInfo.ioFlFndrInfo.fdFlags,bCustomIcn)) // custom
- fileBits[5] = TRUE;
- else
- fileBits[5] = FALSE;
-
- if (MyBitTst(pCBlk->hFileInfo.ioFlFndrInfo.fdFlags,bInited)) // inited
- fileBits[4] = TRUE;
- else
- fileBits[4] = FALSE;
-
- fileBits[0] = FALSE; // dirty flag clear
- }
- }
-
-
- /* The reverse of InfoIn; takes the file's or folder's information from DI's array
- and fills out the OS' data structure
- */
- void
- InfoOut(unsigned short *pFSflags, FSSpecPtr pFSS, CInfoPBPtr pCBlk)
- {
- OSErr lErr;
- short lCtr;
-
- if (!MyBitTst(pCBlk->hFileInfo.ioFlAttrib,bIsDir)) { // if not dir
-
- for (lCtr = bIsShared; lCtr <= bIsAlias; lCtr++)
- MyBitSetClr(pFSflags, lCtr, fileBits[lCtr]);
-
- if (fileBits[1]) // file lock
- lErr = FSpSetFLock(pFSS);
- else
- lErr = FSpRstFLock(pFSS);
- }
- else { // it's a dir
- MyBitSetClr(pFSflags, bInvisible, fileBits[7]);
- MyBitSetClr(pFSflags, bNameLock, fileBits[6]);
- MyBitSetClr(pFSflags, bCustomIcn, fileBits[5]);
- MyBitSetClr(pFSflags, bInited, fileBits[4]);
- }
- }
-
-
- /* ModalDialog filterProc
- In addition to the standard key support, it also supports Cmd-Q as cancel
- */
- pascal Boolean
- MyStdKeyFilter(DialogPtr pDial, EventRecord *pEventRec, short *pItemHit)
- {
- unsigned char lKey;
-
- if ((pEventRec->what == keyDown) || (pEventRec->what == autoKey)) {
- lKey = pEventRec->message & 0xFF;
- switch (lKey) {
- case 13: case 3: { // if return or enter keys
- *pItemHit = 1;
- FlashItem(pDial, 1);
- return TRUE;
- }
- case 27: case '.': case '>': { // if esc or cmd-.
- if ((pEventRec->modifiers & cmdKey) || (lKey == 27)) {
- *pItemHit = 2;
- FlashItem(pDial, 2);
- return TRUE;
- }
- }
- case 'q': case 'Q': {
- if (pEventRec->modifiers & cmdKey) {
- *pItemHit = 2;
- FlashItem(pDial, 2);
- gAbort = TRUE;
- return TRUE;
- }
- }
- default:
- return FALSE;
- }
- }
- else
- return FALSE;
- }
-
-
- /* Routine called if the thing in question is a file. This actually does the work */
- void
- ItsAFile(FSSpecPtr pFSS, CInfoPBRec *pCBlk)
- {
- OSErr lErr;
-
- FInfo lFinfo;
-
- Str255 lNameStr;
-
- DialogPtr lDial;
-
- short lCtr;
- short lItemHit;
-
-
- lErr = FSpGetFInfo(pFSS, &lFinfo);
-
- if (!gChgAll) {
- InfoIn(lFinfo.fdFlags, pCBlk);
-
- lDial = GetNewDialog(130, nil, (WindowPtr) -1);
- DefBut(lDial);
-
- /* set up the dialog */
- // Probably should consider NOT using BlockMove
- // as it is VERY inefficient on an '040 due to CacheFlush
- BlockMove(&pFSS->name, &lNameStr, pFSS->name[0]+1);
- gTypeStr[0] = 4;
- BlockMove(&lFinfo.fdType, &gTypeStr[1], 4);
- gCreaStr[0] = 4;
- BlockMove(&lFinfo.fdCreator, &gCreaStr[1], 4);
- SetTxtItem(lDial, 5, (Str255 *) &lNameStr);
- SetTxtItem(lDial, 3, (Str255 *) &gTypeStr);
- SetTxtItem(lDial, 4, (Str255 *) &gCreaStr);
-
-
- for (lCtr = bIsShared; lCtr <= bInited; lCtr++)
- CheckBox(lDial, lCtr, fileBits[lCtr]);
- for (lCtr = bCustomIcn; lCtr <= bIsAlias; lCtr++)
- CheckBox(lDial, lCtr, fileBits[lCtr]);
-
- CheckBox(lDial, 16, fileBits[1]); // locked
-
- if (gOnlyOne)
- DisEnAble(lDial, 18, FALSE);
-
- DrawDialog(lDial);
- SelIText(lDial, 3, 0, 32767);
-
- do {
- gAbort = FALSE;
- ModalDialog(MyStdKeyFilter, &lItemHit);
- switch (lItemHit) {
- case 1: { // OK
- break;
- }
- case 2: { // cancel
- fileBits[0] = FALSE; // clear dirty flag
- break;
- }
- case 16: { // locked state
- ToggleBit(&fileBits[1]);
- CheckBox(lDial, 16, fileBits[1]);
- break;
- }
- case 18: { // change all
- gChgAll = TRUE;
- gIsFiles = TRUE;
- break;
- }
- default: { // the other bits
- ToggleBit(&fileBits[lItemHit]);
- CheckBox(lDial, lItemHit, fileBits[lItemHit]);
- break;
- }
- }
- } while ((lItemHit != 1) && (lItemHit != 2) && (lItemHit != 18));
-
- HideWindow(lDial);
-
- if ((lItemHit != 2) && (!gAbort)) { // if not cancel
- GetTxtItem(lDial, 3, (Str255 *) &gTempStr);
-
- if (!EqualString(gTempStr, gTypeStr, TRUE, TRUE)) {
- // Probably should consider NOT using BlockMove
- // as it is VERY inefficient on an '040 due to CacheFlush
- BlockMove(&gTempStr[1], &lFinfo.fdType, 4);
- BlockMove(&gTempStr[1], &gTypeStr[1], 4);
- fileBits[0] = TRUE;
- }
- GetTxtItem(lDial, 4, (Str255 *) &gTempStr);
- if (!EqualString(gTempStr, gCreaStr, TRUE, TRUE)) {
- // Probably should consider NOT using BlockMove
- // as it is VERY inefficient on an '040 due to CacheFlush
- BlockMove(&gTempStr[1], &lFinfo.fdCreator, 4);
- BlockMove(&gTempStr[1], &gCreaStr[1], 4);
- fileBits[0] = TRUE;
- }
- GetTxtItem(lDial, 5, (Str255 *) &gTempStr);
- if (!EqualString(gTempStr, lNameStr, TRUE, TRUE)) {
- if (gTempStr[0] > 32)
- gTempStr[0] = 32;
- lErr = FSpRstFLock(pFSS); // will be reset later if necessary
- lErr = FSpRename(pFSS, gTempStr);
-
- if (lErr == -48) {
- lErr = Alert(132, nil);
- fileBits[0] = FALSE;
- }
- else {
- BlockMove(&gTempStr, &pFSS->name, gTempStr[0]+1);
- fileBits[0] = TRUE;
- }
- }
- }
- DisposDialog(lDial);
- }
- else {
- fileBits[0] = TRUE;
- // Probably should consider NOT using BlockMove
- // as it is VERY inefficient on an '040 due to CacheFlush
- BlockMove(&gTypeStr[1], &lFinfo.fdType, 4);
- BlockMove(&gCreaStr[1], &lFinfo.fdCreator, 4);
- }
-
- if (fileBits[0]) { // dirty flag is set
- InfoOut(&lFinfo.fdFlags, pFSS, pCBlk);
-
- pCBlk->hFileInfo.ioDirID = pFSS->parID;
- if (gChgAll)
- pCBlk->hFileInfo.ioNamePtr = 0L;
- else
- pCBlk->hFileInfo.ioNamePtr = (StringPtr) &gTempStr;
- lErr = PBSetCatInfo(pCBlk, FALSE);
-
- lErr = FSpSetFInfo(pFSS, &lFinfo);
- }
-
- if (gAbort)
- SendQuitToSelf(); // send ourselves a quit!
- }
-
-
- /* Routine called if the thing in question is a folder. This actually does the work */
- void
- ItsADir(FSSpecPtr pFSS, CInfoPBRec *pCBlk)
- {
- OSErr lErr;
-
- FInfo lFinfo;
- HParamBlockRec lHBlk;
-
- Str255 lNameStr;
-
- DialogPtr lDial;
-
- short lCtr;
- short lItemHit;
-
-
- /*
- HACK ALERT!!!!!!
-
- In order to keep the MPW C compiler from complaining about a variable
- use before initialization, we make the following bogus call. Fortunately,
- contrary to IM VI, this call doesn't work for directories and the InfoIn
- routine does NOT look at that param for directories.
- */
-
- lErr = FSpGetFInfo(pFSS, &lFinfo);
- lErr = noErr;
-
- if (!gChgAll) {
- InfoIn(lFinfo.fdFlags, pCBlk);
-
- lDial = GetNewDialog(129, nil, (WindowPtr) -1);
- DefBut(lDial);
-
- /* set up the dialog */
-
- BlockMove(&pFSS->name, &lNameStr, pFSS->name[0]+1);
- SetTxtItem(lDial, 3, (Str255 *) &lNameStr);
-
- for (lCtr = 4; lCtr <= 7; lCtr++)
- CheckBox(lDial, lCtr, fileBits[lCtr]);
-
- if (gOnlyOne)
- DisEnAble(lDial, 8, FALSE);
-
- DrawDialog(lDial);
- SelIText(lDial, 3, 0, 32767);
-
- do {
- ModalDialog(MyStdKeyFilter, &lItemHit);
- switch (lItemHit) {
- case 1: { // OK
- break;
- }
- case 2: { // cancel
- fileBits[0] = FALSE; // clear dirty flag
- break;
- }
- case 8: { // change all
- gChgAll = TRUE;
- gIsFiles = FALSE;
- break;
- }
- default: { // the other bits
- ToggleBit(&fileBits[lItemHit]);
- CheckBox(lDial, lItemHit, fileBits[lItemHit]);
- break;
- }
- }
- } while ((lItemHit != 1) && (lItemHit != 2) && (lItemHit != 8));
-
- HideWindow(lDial);
-
- if (gAbort) { // cmd q
- DisposDialog(lDial);
- ExitToShell();
- }
-
- if (lItemHit != 2) { // if not cancel
- GetTxtItem(lDial, 3, (Str255 *) &gTempStr);
-
- if (!EqualString(gTempStr, lNameStr, TRUE, TRUE)) {
- if (gTempStr[0] > 32)
- gTempStr[0] = 32;
-
- lHBlk.ioParam.ioNamePtr = (StringPtr) &lNameStr;
- lHBlk.ioParam.ioVRefNum = pFSS->vRefNum;
- lHBlk.ioParam.ioMisc = (Ptr) &gTempStr;
- lHBlk.fileParam.ioDirID = pFSS->parID;
- lErr = PBHRename(&lHBlk, FALSE); // rename the dir
-
- if (lErr == -48) {
- lErr = Alert(132, nil);
- fileBits[0] = FALSE;
- }
- else
- fileBits[0] = TRUE;
-
- }
- }
- DisposDialog(lDial);
- }
- else
- fileBits[0] = true;
-
- if (fileBits[0]) { // dirty flag is set
- InfoOut(&pCBlk->hFileInfo.ioFlFndrInfo.fdFlags, pFSS, pCBlk);
-
- pCBlk->hFileInfo.ioDirID = pFSS->parID;
- if (!gChgAll)
- pCBlk->hFileInfo.ioNamePtr = (StringPtr) &gTempStr;
- lErr = PBSetCatInfo(pCBlk, FALSE);
- }
- }
-
-
- /* This is called by DropShell, once for every FSSpec received via odoc. GetTheInfo
- is simply a dispatcher to ItsAFile and ItsAFolder. Once the alterations have been made
- it also touched the parent dir's modification date, thereby causing the Finder to update
- that directory's window.
- */
- void
- GetTheInfo(FSSpecPtr pFSS)
- {
- OSErr lErr;
-
- CInfoPBRec lCBlk;
-
-
- lCBlk.hFileInfo.ioVRefNum = pFSS->vRefNum;
- lCBlk.hFileInfo.ioNamePtr = (StringPtr) &pFSS->name;
- lCBlk.hFileInfo.ioDirID = pFSS->parID;
- lCBlk.hFileInfo.ioFDirIndex = 0;
- lCBlk.hFileInfo.ioCompletion = 0;
-
- lErr = PBGetCatInfo(&lCBlk, FALSE);
-
- if (!MyBitTst(lCBlk.hFileInfo.ioFlAttrib,bIsDir)) {
- if (gChgAll && (!gIsFiles)) {
- if (!gWarned) {
- ParamText("\pfolders", 0,0,0);
- lErr = Alert(133, nil);
- gWarned = TRUE;
- }
- return;
- }
- else
- ItsAFile(pFSS, &lCBlk);
- }
- else {
- if (gChgAll && gIsFiles) {
- if (!gWarned) {
- ParamText("\pfiles", 0,0,0);
- lErr = Alert(133, nil);
- gWarned = TRUE;
- }
- return;
- }
- else
- ItsADir(pFSS, &lCBlk);
- }
-
- /*
- touch the parent dir's mod date
- We need to do this to get the Finder to update itself on demand!
- */
-
- if (fileBits[0]) {
- if (pFSS->parID != 1) // if it's a vol then reuse the NameStr
- lCBlk.dirInfo.ioNamePtr = 0L;
- lCBlk.dirInfo.ioVRefNum = pFSS->vRefNum;
- lCBlk.dirInfo.ioDrDirID = pFSS->parID;
- lCBlk.dirInfo.ioFDirIndex = 0;
- lCBlk.dirInfo.ioCompletion = 0;
-
- lErr = PBGetCatInfo(&lCBlk, FALSE);
- GetDateTime(&lCBlk.dirInfo.ioDrMdDat);
- lCBlk.dirInfo.ioDrDirID = pFSS->parID;
- lErr = PBSetCatInfo(&lCBlk, FALSE);
-
- lErr = FlushVol(nil, pFSS->vRefNum);
- }
- }
-